package com.xinyun.server;

import com.xinyun.server.db.ElectricMeter;
import com.xinyun.server.db.dao.ElectricMeterDao;
import com.xinyun.server.protocol.ProtocolData;
import com.xinyun.server.protocol.ProtocolDataHeader;
import com.xinyun.server.protocol.receive.InverterData;
import com.xinyun.server.protocol.receive.InverterWarnData;
import com.xinyun.server.protocol.receive.LeakWarnData;
import com.xinyun.server.protocol.receive.RegisterBoardId;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


/**
 * Created by bubusy on 16/5/21.
 */
public class ProtocolHandler extends ChannelInboundHandlerAdapter {

    private Log log = LogFactory.getLog(ProtocolHandler.class);

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ProtocolData pd = (ProtocolData) msg;
        log.debug(pd);
        try {
            int msgType = pd.getHeader().getMsgType();

            switch (msgType) {
                case 1:
                    //注册board id
                    this.handleBoardId(ctx, pd);
                    break;
                case 3:
                    //心跳处理
                    this.handleHeartbeat(ctx, pd);
                    break;
                case 9:
                    this.handleWarn(ctx, pd);
                    break;
                case 7:
                    this.handleInverterData(ctx, pd);
                    break;
                case 11:
                    this.handleOneInverterData(ctx, pd);
                    break;
                default:
                    log.info("无效的协议, msg type: " + msgType);
                    break;
            }

        } finally {
            pd.release();
        }
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        ChannelManager.addChannel(ctx.channel());
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }


    private void handleHeartbeat(ChannelHandlerContext channelHandlerContext, ProtocolData protocolData) {
        //心跳数据不做处理
        return;

    }

    private void handleBoardId(ChannelHandlerContext channelHandlerContext, ProtocolData protocolData) {
        RegisterBoardId registerBoardId = RegisterBoardId.parseFromProtocolData(protocolData);
        String boardId = registerBoardId.boardId;
        ChannelManager.updateChannelBoardId(channelHandlerContext.channel(), boardId);
    }

    private void handleWarn(ChannelHandlerContext channelHandlerContext, ProtocolData protocolData) {
        ProtocolDataHeader header = protocolData.getHeader();
        if (header.getB4() == 1) {
            InverterWarnData inverterWarnData = InverterWarnData.parseFromProtocolData(protocolData);
            log.debug(inverterWarnData);

            Channel channel = channelHandlerContext.channel();
            String boardId = ChannelManager.getBoardIdByChannel(channel);

            if (this.boardIdIsExist(boardId)) {
                this.saveInverterWarnData(inverterWarnData, boardId);
            } else {
                log.info("boardId: " + boardId + "未登记");
            }

            inverterWarnData.release();
        }
        if (header.getB4() == 2) {
            LeakWarnData leakWarnData = LeakWarnData.parseFromProtocolData(protocolData);

            Channel channel = channelHandlerContext.channel();
            String boardId = ChannelManager.getBoardIdByChannel(channel);

            if (this.boardIdIsExist(boardId)) {
                this.saveLeakWarnData(leakWarnData, boardId);


                //TODO send warn use wechat


                String url = "http://phaethon.yanzijia.cn/wx/notify_security_msg";

                HttpPost post = new HttpPost(url);
                List<NameValuePair> params = new ArrayList<NameValuePair>();
                params.add(new BasicNameValuePair("meter_id", boardId));
                params.add(new BasicNameValuePair("content", "漏电警报,漏电量: " + leakWarnData.currentLeak / 100.0 + "安"));
                params.add(new BasicNameValuePair("time", leakWarnData.time));

                try {
                    post.setEntity(new UrlEncodedFormEntity(params, "utf-8"));
                    HttpResponse httpResponse = HttpClients.createDefault().execute(post);
                    if (httpResponse.getStatusLine().getStatusCode() == 200) {
                        log.info("发送警报通知成功!");
                    } else {
                        log.info("发送警报通知失败!");
                    }
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                } catch (ClientProtocolException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            } else {
                log.info("boardId: " + boardId + "未登记");
            }

            leakWarnData.release();


        }

    }

    private void handleInverterData(ChannelHandlerContext channelHandlerContext, ProtocolData protocolData) {
        InverterData inverterData = InverterData.parseFromProtocolData(protocolData);
        log.debug(inverterData);
        if (inverterData != null) {
            //TODO

            Channel channel = channelHandlerContext.channel();
            String boardId = ChannelManager.getBoardIdByChannel(channel);

            if (this.boardIdIsExist(boardId)) {
                this.saveInverterData(inverterData, boardId);
            } else {
                log.info("boardId: " + boardId + "未登记");
            }

            inverterData.release();

        }
        //TODO
    }

    private void handleOneInverterData(ChannelHandlerContext channelHandlerContext, ProtocolData protocolData) {
        InverterData inverterData = InverterData.parseFromProtocolData(protocolData);
        log.debug(inverterData);
        if (inverterData != null) {
            //TODO
            Channel channel = channelHandlerContext.channel();
            String boardId = ChannelManager.getBoardIdByChannel(channel);

            if (this.boardIdIsExist(boardId)) {
                this.saveInverterData(inverterData, boardId);
            } else {
                log.info("boardId: " + boardId + "未登记");
            }
            inverterData.release();

        }
        //TODO
    }


    private boolean boardIdIsExist(String boardId) {
        ElectricMeterDao electricMeterDao = ElectricMeterDao.getInstance();
        ElectricMeter electricMeter = electricMeterDao.findByMeterId(boardId);
        if (electricMeter == null) {
            return false;
        } else {
            return true;
        }

    }

    private void saveInverterData(InverterData inverterData, String boardId) {
        QueryRunner runner = new QueryRunner(DB.dataSource);


        String sql = "insert into z_phaethon_meter_data " +
                "(meter_id,DCU1,DCI1,DCU2,DCI2,DCU3,DCI3,DCU4,DCI4,ACUA,ACIA,ACUB,ACIB,ACUC,ACIC," +
                "IVTemp,TotGenCap,IVStatus,IVError,IVMode,FR,IVRun,MonthGenCap,LastMonthGenCap,DayGenCap,LastDayGenCap," +
                "PowerLimitPercent,ActivePower,ReactivePower,ApparentPower,PowerFactor,IVType,board_temp1,board_temp2," +
                "current_leak,board_sum_gen,board_sum_use,board_time,created_at) " +
                "values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";

        Date boardTime = null;
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd H:m:s");
            boardTime = sdf.parse(inverterData.time);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        try {

            runner.update(sql, boardId, inverterData.dcu1 / 10.0, inverterData.dci1 / 10.0, inverterData.dcu2 / 10.0, inverterData.dci2 / 10.0,
                    inverterData.dcu3 / 10.0, inverterData.dci3 / 10.0, inverterData.dcu4 / 10.0, inverterData.dci4 / 10.0, inverterData.acua / 10.0, inverterData.acia / 10.0,
                    inverterData.acub / 10.0, inverterData.acib / 10.0, inverterData.acuc / 10.0, inverterData.acic / 10.0, inverterData.ivtemp / 10.0, inverterData.tolgencap,
                    inverterData.ivstatus, inverterData.iverror, inverterData.ivmode, inverterData.fr / 100.0, inverterData.ivrun, inverterData.monthgencap,
                    inverterData.lastmonthgencap, inverterData.daygencap / 10.0, inverterData.lastdaygencap / 10.0, inverterData.powerlimitpercent / 100.0,
                    inverterData.activepower, inverterData.reactivepower, inverterData.apparentpower, inverterData.powerfactor,
                    inverterData.ivtype, inverterData.boardtemp1 / 10.0, inverterData.boardtemp2 / 10.0, inverterData.currentleak / 100.0,
                    inverterData.boardsumgen, inverterData.boardsumuse, boardTime, new Date());

            log.debug("save inverter data to db success");
        } catch (SQLException e) {
            log.debug(e);
            e.printStackTrace();
            DbUtils.printStackTrace(e);
        } finally {

            //DbUtils.closeQuietly();
        }

    }


    private void saveInverterWarnData(InverterWarnData inverterWarnData, String boardId) {
        QueryRunner runner = new QueryRunner(DB.dataSource);


        String sql = "insert into z_phaethon_meter_warn_data " +
                "(meter_id,DCU1,DCI1,DCU2,DCI2,DCU3,DCI3,DCU4,DCI4,ACUA,ACIA,ACUB,ACIB,ACUC,ACIC," +
                "IVTemp,TotGenCap,IVStatus,IVError,IVMode,FR,IVRun,MonthGenCap,LastMonthGenCap,DayGenCap,LastDayGenCap," +
                "PowerLimitPercent,ActivePower,ReactivePower,ApparentPower,PowerFactor,IVType,board_temp1,board_temp2," +
                "current_leak,board_sum_gen,board_sum_use,board_time,created_at) " +
                "values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";

        Date boardTime = null;
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd H:m:s");
            boardTime = sdf.parse(inverterWarnData.time);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        try {

            runner.update(sql, boardId, inverterWarnData.dcu1 / 10.0, inverterWarnData.dci1 / 10.0, inverterWarnData.dcu2 / 10.0, inverterWarnData.dci2 / 10.0,
                    inverterWarnData.dcu3 / 10.0, inverterWarnData.dci3 / 10.0, inverterWarnData.dcu4 / 10.0, inverterWarnData.dci4 / 10.0, inverterWarnData.acua / 10.0, inverterWarnData.acia / 10.0,
                    inverterWarnData.acub / 10.0, inverterWarnData.acib / 10.0, inverterWarnData.acuc / 10.0, inverterWarnData.acic / 10.0, inverterWarnData.ivtemp / 10.0, inverterWarnData.tolgencap,
                    inverterWarnData.ivstatus, inverterWarnData.iverror, inverterWarnData.ivmode, inverterWarnData.fr / 100.0, inverterWarnData.ivrun, inverterWarnData.monthgencap,
                    inverterWarnData.lastmonthgencap, inverterWarnData.daygencap / 10.0, inverterWarnData.lastdaygencap / 10.0, inverterWarnData.powerlimitpercent / 100.0,
                    inverterWarnData.activepower, inverterWarnData.reactivepower, inverterWarnData.apparentpower, inverterWarnData.powerfactor,
                    inverterWarnData.ivtype, inverterWarnData.boardtemp1 / 10.0, inverterWarnData.boardtemp2 / 10.0, inverterWarnData.currentleak / 100.0,
                    inverterWarnData.boardsumgen, inverterWarnData.boardsumuse, boardTime, new Date());

            log.debug("save inverter warn data to db success");
        } catch (SQLException e) {
            log.debug(e);
            e.printStackTrace();
            DbUtils.printStackTrace(e);
        } finally {

            //DbUtils.closeQuietly();
        }

    }


    private void saveLeakWarnData(LeakWarnData leakWarnData, String boardId) {
        QueryRunner runner = new QueryRunner(DB.dataSource);


        String sql = "insert into z_phaethon_meter_leak_warn_data " +
                "(meter_id,current_leak,board_time,created_at) " +
                "values(?,?,?,?";

        Date boardTime = null;
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd H:m:s");
            boardTime = sdf.parse(leakWarnData.time);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        try {

            runner.update(sql, boardId, leakWarnData.currentLeak / 100.0, boardTime, new Date());

            log.debug("save leak warn data to db success");
        } catch (SQLException e) {
            log.debug(e);
            e.printStackTrace();
            DbUtils.printStackTrace(e);
        } finally {

            //DbUtils.closeQuietly();
        }

    }
}
